/*
 * Copyright 2007 David R Kirkland 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");  
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */

using System.IO;
using System.Net;
using NetSpider.Retrieval.Policies;

namespace NetSpider.Retrieval
{
    public class HttpRetriever : IRetriever
    {
        private readonly string _temporaryFolder;

        public HttpRetriever(string temporaryFolder)
        {
            _temporaryFolder = temporaryFolder;
        }

        public string[] GetSupportedUriSchemas()
        {
            return new string[] { "http", "https" };
        }

        public IRetrievalResult Retrieve(string uri, OnRetrievalProgressHandler onRetrievalProgressMethod)
        {
            HttpWebRequest request = CreateRequest(uri);
            return RetrieveContent(request, onRetrievalProgressMethod);
        }

        public IRetrievalResult Retrieve(IFetchRequest fetchRequest, OnRetrievalProgressHandler onRetrievalProgressMethod)
        {
            HttpWebRequest httpRequest = CreateRequest(fetchRequest.RequestedUri.ToString());
            IRetrievalResult result =  RetrieveContent(httpRequest, onRetrievalProgressMethod);
            fetchRequest.Update(result);
            return result;
        }

        public string Name
        {
            get { return "HttpRetriever"; }
        }

        private HttpWebRequest CreateRequest(string uri)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
            request.UserAgent = "";
            request.Headers.Add("From", "");
            return request;
        }

        private RetrievalResult RetrieveContent(WebRequest httpRequest, 
                                                OnRetrievalProgressHandler onRetrievalProgressMethod)
        {
            RetrievalResult result;
            IContent content;
            using (WebResponse httpResponse = httpRequest.GetResponse())
            {
                //check policy for contentType allowal?
                using (Stream stream = httpResponse.GetResponseStream())
                {
                    string contentFile = Path.Combine(_temporaryFolder, Path.GetRandomFileName());
                    Stream fileStream = FileHelper.CreateFile(contentFile);

                    byte[] buffer = new byte[1024];
                    int n;
                    RetrievalDecision decision;
                    do
                    {
                        n = stream.Read(buffer, 0, buffer.Length);
                        fileStream.Write(buffer, 0, n);
                        decision = onRetrievalProgressMethod.Invoke(fileStream.Length);
                    } while (n > 0 && decision == RetrievalDecision.ContinueFetching);

                    stream.Close();

                    if (decision == RetrievalDecision.ContinueFetching)
                    {
                        fileStream.Position = 0;
                        byte[] bytesRetrieved = new byte[fileStream.Length];
                        fileStream.Read(bytesRetrieved, 0, bytesRetrieved.Length);

                        content =
                            new FileStoredContent(httpRequest.RequestUri.ToString(), httpResponse.ContentType,
                                                  contentFile);
                        result = new RetrievalResult(content);

                        fileStream.Close();
                    }
                    else
                    {
                        result = new RetrievalResult(decision);
                    }
                }
            }

            return result;
        }
    }
}
